# 基于随机算法的模版AI
# 此处采取的算法为优先在己方领域下, 己方满则在对方领域随机下

# 参赛队伍的AI要求:
#
# 须写在Player类里
#
# 须实现两个方法:
#
# __init__(self, isFirst, array):
#   -> 初始化
#   -> 参数: isFirst是否先手, 为bool变量, isFirst = True 表示先手
#   -> 参数: array随机序列, 为一个长度等于总回合数的list
#
# output(self, currentRound, board, mode):
#   -> 给出己方的决策(下棋的位置或合并的方向)
#   -> 参数: currentRound当前轮数, 为从0开始的int
#   -> 参数: board棋盘对象
#   -> 参数: mode模式, mode = 'position' 对应位置模式, mode = 'direction' 对应方向模式, 如果为 '_position' 和 '_direction' 表示在对应模式下己方无法给出合法输出
#   -> 返回: 位置模式返回tuple (row, column), row行, 从上到下为0到3的int; column列, 从左到右为0到7的int
#   -> 返回: 方向模式返回direction = 0, 1, 2, 3 对应 上, 下, 左, 右
#   -> 返回: 在己方无法给出合法输出时, 对返回值不作要求
#
# 其余的属性与方法请自行设计
import random
import math
import copy

class Stack:
    def __init__(self):
        self.items = []

    def isEmpty(self):
        return self.items == []

    def push(self, item):
        self.items.append(item)

    def pop(self):
        return self.items.pop()

    def peek(self):
        return self.items[len(self.items) - 1]

    def size(self):
        return len(self.items)



class Player:
    def __init__(self, isFirst, array):
        # 初始化
        self.isFirst = isFirst
        self.array = array
        self.board = None
        self.best_direction = None
        self.best_position = None
        # 后期优化可以考虑排一个direction和position决策的优先队列，防止best direction或position是None
        # 代码中暂时让best决策为None时选择随机一个方向
        self.depth = 9  # 待改，而且一到10就报错，还没弄明白怎么回事（，现在最大是9
        self.another = None  # 轮到己方下棋时，若下在己方棋盘则应该下的位置
        self.current_round = 0  # 表示当前进行的回合数
        # 现在还有一个问题是current_round需不需要复原。目前是没有写复原的。
        self.prev_stack = Stack()  # 用于回溯之前的棋盘，即用于cancel move

    def output(self, currentRound, board, mode):  # 由userinterface.py可得，主程序中调用output时传入的board参数为copy完毕的board对象
        self.board = board.copy()  # 注意：不能用deepcopy，会报错，chessboard类的copy方法已经是深拷贝
        self.current_round = currentRound
        if len(self.board.getNone(self.isFirst)) <= 2:
            self.depth = 2
        if len(self.array) - self.current_round <= 10:
            self.depth = 2
        if mode == 'position':  # 给出己方下棋的位置
            '''another = board.getNext(self.isFirst, currentRound)  # 己方的允许落子点
            if another != (): return another  # 己方领地有可以下棋的地方，则优先选择在己方下棋
            # 如果己方领地无可下棋位置，则再考虑是否在对方那里下棋
            available = board.getNone(not self.isFirst)  # 对方的允许落子点
            if not available:   # 整个棋盘已满
                return None
            else:
                from random import choice
                return choice(available)'''
            self.another = self.board.getNext(self.isFirst, currentRound)
            return self.choose_position()
        elif mode == 'direction':  # 给出己方合并的方向
            '''from random import shuffle
            directionList = [0, 1, 2, 3]
            shuffle(directionList)
            for direction in directionList:
                #board.move()返回棋盘是否变化，若为False则是非法行为。
                if board.move(self.isFirst, direction): return direction ''' #如果这个方向是合法方向，就选择这个方向进行合并。
            return self.choose_direction()
        else:  # mode参数为_position或者_direction
            return


    def invade(self):
        lst = [(0, 4), (1, 5), (2, 6), (3, 7)]  # 用于转换先后手时列数不同的辅助列表
        # 对方即将合成较大棋子时若可以阻挠则选取其路径上的空格
        value = 5
        position = None
        x = 1 if self.isFirst else 0
        for row in range(4):  # 遍历对方的每一行
            valueList = [self.board.getValue((row, column)) for column in range(lst[0][x], lst[3][x]+1)]
            # 若对方某一行中有两个等级大于等于5的棋子，且中间为空格，则取出该空格的位置
            # 若存在不止一个这样的位置，则选取等级更大时的空格位置
            if valueList[0] == valueList[2] and valueList[1] == 0 and valueList[0] >= value:
                value = valueList[0]
                position = (row, lst[1][x])
            elif valueList[1] == valueList[3] and valueList[2] == 0 and valueList[1] >= value:
                value = valueList[0]
                position = (row, lst[2][x])
            elif valueList[0] == valueList[3] and valueList[1] == 0 and valueList[2] == 0 and valueList[0] >= value:
                value = valueList[0]
                position = (row, lst[1][x])
        for column in range(lst[0][x], lst[3][x]+1):  # 遍历对方的每一列
            valueList = [self.board.getValue((row, column)) for row in range(4)]
            if valueList[0] == valueList[2] and valueList[1] == 0 and valueList[0] >= value:
                value = valueList[0]
                position = (1, column)
            elif valueList[1] == valueList[3] and valueList[2] == 0 and valueList[1] >= value:
                value = valueList[0]
                position = (2, column)
            elif valueList[0] == valueList[3] and valueList[1] == 0 and valueList[2] == 0 and valueList[0] >= value:
                value = valueList[0]
                position = (1, column)
        if position != None:
            return position
        # 选取对方空格列表中的孤岛
        emptyList = self.board.getNone(self.isFirst)
        directionList = [(-1, 0), (1, 0), (0, -1), (0, 1)]  # 计算空格的上下左右位置时的辅助列表
        islandList = []  # 孤岛列表
        for cell in emptyList:
            if cell[0] <= 2 and cell[0] >= 1 and cell[1] <= lst[2][x] and cell[1] >= lst[1][x]:  # 当空格在对方领域中间时
                num = 0  # 计算该空格周围的棋子数
                for i in range(4):
                    newrow = cell[0] + directionList[i][0]
                    newcol = cell[1] + directionList[i][1]
                    newpos = (newrow, newcol)
                    if self.board.getValue(newpos) != 0 and self.board.getValue(newpos) != 1:
                        num += 1
                if num == 4:
                    islandList.append(cell)
            elif ((cell[0] == 0 or cell[0] == 3) and cell[1] <= lst[2][x] and cell[1] >= lst[1][x]
                  or cell[0] <= 2 and cell[0] >= 1 and (cell[1] == lst[0][x] or cell[1] == lst[3][x])):  # 当空格在对方领域非角落的边界时
                num = 0  # 计算该空格周围的棋子数
                for i in range(4):
                    newrow = cell[0] + directionList[i][0]
                    newcol = cell[1] + directionList[i][1]
                    newpos = (newrow, newcol)
                    if (newpos[0] <= 3 and newpos[0] >= 0 and newpos[1] <= lst[3][x] and newpos[1] >=lst[0][x]  # newpos在对方领域内
                            and self.board.getValue(newpos) != 0 and self.board.getValue(newpos) != 1):
                        num += 1
                if num == 3:
                    islandList.append(cell)
            elif ((cell[0] == 0 or cell[0] == 3) and (cell[1] == lst[0][x] or cell[1] == lst[3][x])):  # 当空格在对方领域的角落时
                num = 0  # 计算该空格周围的棋子数
                for i in range(4):
                    newrow = cell[0] + directionList[i][0]
                    newcol = cell[1] + directionList[i][1]
                    newpos = (newrow, newcol)
                    if (newpos[0] <= 3 and newpos[0] >= 0 and newpos[1] <= lst[3][x] and newpos[1] >= lst[0][x]  # newpos在对方领域内
                            and self.board.getValue(newpos) != 0 and self.board.getValue(newpos) != 1):
                        num += 1
                if num == 2:
                    islandList.append(cell)
        if islandList != []:
            return islandList[0]
        else:
            return None


    def choose_position(self):
        # 优先进攻，其次下在自己这里，其次下在对方那里（具体下在哪个位置？需要决策！）
        if self.invade() != None :
            return self.invade()
        # self.get_PositionValue(self.depth, -1000000, 1000000, -1, self.isFirst)
        self.best_position = self.another
        if self.best_position:
            return self.best_position
        else:   # self.another可能为None（己方棋盘满了）
            self.get_PositionValue(self.depth, -1000000, 1000000, -1, self.isFirst)
            if self.best_position:
                return self.best_position
            available = self.board.getNone(not self.isFirst)  # 对方的允许落子点
            if not available:  # 整个棋盘已满
                return None
            else:
                from random import choice
                return choice(available)



    def contest(self):
        # 分为先后手 判断我方棋盘位置
        judgelist=[]
        if self.isFirst:  
            for col in range(1,8):
                for row in range(0,4):
                    judgeyou=(row,col)
                    judgeme=(row,col-1)
                    #按照从左往右第一个出现两方棋子交界处
                    if self.board.getValue(judgeyou)!=0 and (not self.board.getBelong(judgeyou)) and \
                       self.board.getValue(judgeme)!=0 and self.board.getBelong(judgeme):
                        #前方没有危险
                        if self.board.getValue(judgeyou)!=self.board.getValue(judgeme):
                            pass
                        #前方有危险
                        elif self.board.getValue(judgeyou)==self.board.getValue(judgeme):
                            if row!=0:
                                judgeyouup=(row-1,col)
                                judgelist.append(self.board.getValue(judgeyouup))
                            if row!=3:
                                judgeyoudown=(row+1,col)
                                judgelist.append(self.board.getValue(judgeyoudown))
                            if col!=7:
                                judgeyouright=(row,col+1)
                                judgelist.append(self.board.getValue(judgeyouright))
                            self.best_direction = 3
                            for value in judgelist:
                                if value == self.board.getValue(judgeme)+1:  # judgelist中只要有一个value满足这个条件就得往左撤退
                                    self.best_direction = 2
                                else:
                                    continue
                            # 若没有value满足这个条件，则可以往右吃

        else:
            for col in range(6,-1,-1):  # 从6到0
                for row in range(0,4):
                    judgeyou=(row,col)
                    judgeme=(row,col+1)
                    #按照从左往右第一个出现两方棋子交界处
                    if self.board.getValue(judgeyou)!=0 and (not self.board.getBelong(judgeyou)) and \
                       self.board.getValue(judgeme)!=0 and self.board.getBelong(judgeme):
                        #前方没有危险
                        if self.board.getValue(judgeyou)!=self.board.getValue(judgeme):
                            pass
                        #前方有危险
                        elif self.board.getValue(judgeyou)==self.board.getValue(judgeme):
                            if row!=0:
                                judgeyouup=(row-1,col)
                                judgelist.append(self.board.getValue(judgeyouup))
                            if row!=3:
                                judgeyoudown=(row+1,col)
                                judgelist.append(self.board.getValue(judgeyoudown))
                            if col!=0:  # col肯定不会等于7啊，是不等于0吧
                                judgeyouleft=(row,col-1)
                                judgelist.append(self.board.getValue(judgeyouleft))
                            self.best_direction = 2
                            for value in judgelist:
                                if value == self.board.getValue(judgeme)+1:  # judgelist中只要有一个value满足这个条件就得往右撤退
                                    self.best_direction = 3
                                else:
                                    continue
                            # 若没有value满足这个条件，则可以往左吃

                            
   
    def choose_direction(self):
        self.contest()  # 先判断是否需要撤回
        if self.best_direction and self.board.move(self.isFirst, self.best_direction):
            return self.best_direction
        else:
            self.get_DirectionValue(self.depth, -1000000, 1000000, -1, self.isFirst)
            if self.best_direction:
                return self.best_direction
            else:
                from random import shuffle
                directionList = [0, 1, 2, 3]
                shuffle(directionList)
                for direction in directionList:
                    # board.move()返回棋盘是否变化，若为False则是非法行为。
                    if self.board.move(self.isFirst, direction):
                        return direction



    def get_BoardValue(self,player):  # player=-1时为己方，player=1时为对方
        isFirst = self.isFirst if player == -1 else (not self.isFirst)
        #value = -math.exp((self.estimateValue(isFirst))) * player
        value = self.estimateValue(isFirst)  # 原先是-(self.estimateValue(isFirst))*player
        return value

    def get_PositionValue(self, depth, alpha, beta, player, isFirst):   # isFirst表示当前player是否为先手(bool)
        # 运用negamax算法获取这一步决策的value值
        global prev_stack

        if depth == 0:
            return self.get_BoardValue(player)-self.get_BoardValue(-player)

        positionList = []
        available = self.board.getNone(not isFirst)
        another = self.board.getNext(isFirst, self.current_round)
        if another != ():  # 优先下在己方棋盘；当己方无处可下时再下在对方棋盘。
            positionList.append(another)
        else:
            if available:
                from random import choice
                positionList += [choice(available)]
                # 注意：available过于庞大且漫无目的，后续要改，选择出几个有必要的（比如对方棋盘要进行大数合并时选择在两者中间）
                # 这里仅仅取了available中的随机一个位置

        for position in positionList:
            current_board = self.board.copy()
            self.prev_stack.push(current_board)
            self.board.add(isFirst, position)  # make move

            if isFirst:  # 本层player为先手方，即下一步是另一方选择位置下棋
                value = -self.get_PositionValue(depth - 1, -beta, -alpha, -player, not isFirst)
            else:  # 本层player为后手方，即下一步是另一方选择方向进行合并
                value = -self.get_DirectionValue(depth - 1, -beta, -alpha, -player, not isFirst)

            self.board = self.prev_stack.pop()  # cancel move

            if value >= alpha:
                if depth == self.depth:
                    self.best_position = position
                alpha = value
            if alpha >= beta:
                break
        return alpha


    def get_DirectionValue(self,depth,alpha,beta,player,isFirst):   # isFirst表示当前player是否为先手(bool)
        # 运用negamax算法获取这一步决策的value值
        global prev_stack
        if depth == 0:
            return self.get_BoardValue(player)-self.get_BoardValue(-player)

        # 以下是防守形式，若向左向右走的value一样则优先选择往己方的后方合并。
        if isFirst:
            directionList = [0, 1, 3, 2]
        else:
            directionList = [0, 1, 2, 3]

        for direction in directionList:
            current_board = self.board.copy()
            if self.board.move(isFirst, direction):  # 此合并方向合法时make move
                self.prev_stack.push(current_board)

                if isFirst:  # 本层player为先手方，即下一步是另一方选择方向进行合并
                    value = -self.get_DirectionValue(depth-1, -beta, -alpha, -player, not isFirst)
                else:  # 本层player为后手方，即下一步是另一方选择位置下棋
                    self.current_round += 1  # 下一步就是下一回合了，所以要更新
                    value = -self.get_PositionValue(depth-1, -beta, -alpha, -player, not isFirst)

                self.board = self.prev_stack.pop()  # cancel move

                if value >= alpha:
                    if depth == self.depth:
                        self.best_direction = direction
                    alpha = value
                if alpha >= beta:
                    break
        return alpha




    # 评估函数为estimaValue(self, isFirst)（chessboard类中已有getValue方法了，所以换了个名字）
    # 此函数为客观评价函数，即输入参数 阵营(isFirst) ，输出该阵营在此棋面下的value，不附带有主观性，敌我均可用
    # 将isFirst代表的阵营称为对象方，另一方则称为对方（这也深刻体现了该函数的客观性）
    # isFirst为bool值，isFirst = True相当于isFirst = 1，isFirst = False相当于isFirst = -1

    def estimateValue(self, isFirst):  #计算先手或后手方的棋面value
        smoothnessWeight = 0.12  ####平滑性权重
        monotonicityWeight = 0.23  ####单调性权重
        emptyCellsWeight = 0.21  ####空格数权重
        # islandsWeight = 0    ####孤岛数权重
        figureWeight = 0.42  ####棋子级别权重
        invadeWeight = 0.18  ####入侵对方时的权重
        value = smoothnessWeight * self.smoothnessValue(isFirst) + \
                monotonicityWeight * self.monotonicityValue(isFirst) + \
                emptyCellsWeight * self.emptyCellsValue(isFirst) + \
                figureWeight * self.figureValue(isFirst) + \
                invadeWeight * self.invadeValue(isFirst)
        return value

    def figureValue(self, isFirst):  #将对象方棋子的级别加权求和 得到 棋子级别大小和数量提供的value
        import math
        selfSide = isFirst
        selfChessmanList = self.board.getScore(selfSide)  #对象方所有棋子级别按升序排成的列表
        figurevalue = 0
        for level in selfChessmanList:  #对每个棋子计算其value
            '''此处计算式可更改 但是应有value(2*level)>2*value(level)'''
            figurevalue += math.pow(2.2, level)
        return figurevalue

    def emptyCellsValue(self, isFirst):  #计算对象方空位数value
        import math
        selfSide = isFirst
        selfEmptyCellsNums = len(self.board.getNone(selfSide))  #对象方空位数
        '''此处计算式可更改，但是应有:在空格数较少时，value对空格数的导数较大，
           空格数较大时，value对空格数的导数较小'''
        if selfEmptyCellsNums != 0:
            emptyCellsvalue = math.log(selfEmptyCellsNums, 2)  # 这里有定义域问题，如果selfEmptyCellsNums=0则会报错,故增加一种情况。
            return emptyCellsvalue
        return 0  # 是否输出0，待改

    def islandsValue(self, isFirst):  # 若一个空格 周围没有 其他空格 或者 级别为1的棋子 时，将其称为孤岛，提供负的value
        import math
        selfSide = isFirst
        selfEmptyCellsPosList = self.board.getNone(selfSide)  # 获得对象方所有空格位置的列表
        islandNums = 0  # 孤岛数计数
        directionList = [(-1, 0), (1, 0), (0, -1), (0, 1)]  # 计算空格的上下左右位置时的辅助列表
        for cell in selfEmptyCellsPosList:  # 考虑每一个对象方空格
            isIsland = True  # 用于判断空格是否为孤岛
            i = 0  # 计数君
            # 遍历此空格上下左右的格子
            while i <= 3 and isIsland:
                newrow = cell[0] + directionList[i][0]
                newcol = cell[1] + directionList[i][1]
                newpos = (newrow, newcol)

                if newrow < 0 or newrow > 3:
                    # 行数不在棋盘范围内
                    pass
                elif (newcol - (1 - isFirst)*4) < 0 or (newcol - (1 - isFirst)*4) > 3:
                    # 列数不在对象方棋盘范围内
                    pass
                elif self.board.getValue(newpos) <= 1:  # 若 空格旁的这个格子 级别小于等于1，则其必定是对象方的'2'或者空格
                    isIsland = False

                i += 1

            if isIsland:
                islandNums += 1
        '''此处可更改表达式，但应保证value为负值'''
        islandsvalue = - math.pow(islandNums, 1.2)
        return islandsvalue

    def smoothnessValue(self, isFirst): # 计算对象方棋子的平滑性，不平滑带来的value应为负值
        selfSide = isFirst
        smoothnessvalue = 0   # 初始化平滑性value
        directionList = [(-1, 0), (1, 0), (0, -1), (0, 1)]
        # 遍历棋盘上每一个格子（因为对象方棋子可能在对方棋盘内有分布）
        for row in range(0, 4):
            for col in range(0, 8):
                # 如果此格为对象方的棋子，则要考虑其与邻近的对象方棋子贡献的平滑性value
                if selfSide == self.board.getBelong((row, col)) and\
                      self.board.getValue((row, col)) != 0:
                    # level代表此格棋子的级别
                    level = self.board.getValue((row, col))
                    # 遍历此格棋子上下左右的格子
                    for i in range(4):
                        newrow = row + directionList[i][0]
                        newcol = col + directionList[i][1]
                        # 如果此方向的格子超界，则不用考虑此方向
                        if (newrow) < 0 or (newrow) > 3 or\
                                (newcol) < 0 or (newcol) > 7:
                            pass
                        # 如果此方向的格子上为对象方棋子，则要考虑平滑性影响
                        elif selfSide == self.board.getBelong((newrow, newcol)) and\
                            self.board.getValue((newrow, newcol)) != 0:
                            newLevel = self.board.getValue((newrow, newcol))
                            # deltaLevel代表两棋子的级别差
                            deltaLevel = abs(level - newLevel)
                            '''此处表达式可以修改，但应保证smoothnessvalue非正'''
                            smoothnessvalue -= deltaLevel ** 2

        return smoothnessvalue

    def invadeValue(self, isFirst):  # 建立敌后根据地
        selfSide = isFirst
        enemySide = not isFirst
        invadevalue = 0
        directionList = [(-1, 0), (1, 0), (0, -1), (0, 1)]
        # 对对方的棋盘遍历，
        for row in range(4):
            for col in range(isFirst*4, 4+isFirst*4):

                # 找出对方棋盘中的对象方棋子
                if selfSide == self.board.getBelong((row, col)):

                    # level 为该棋子的级别
                    level = self.board.getValue((row, col))

                    # 对该棋子四个方向的格子进行遍历
                    for i in range(4):
                        newrow = row + directionList[i][0]
                        newcol = col + directionList[i][1]
                        #如果此方向的格子超界，则不用考虑此方向
                        if newrow < 0 or newrow > 3 or\
                            newcol < 0 or newcol > 7:
                            pass

                        # 如果此方向的格子中为对方的等级别棋子，则要考虑入侵带来的value
                        elif enemySide == self.board.getBelong((newrow, newcol)) and\
                              self.board.getValue((newrow, newcol)) == level:
                            # 对象方为先后手决定了value的正负
                            '''此处的表达式可更改，但应保证先后手的value正负号相反'''
                            invadevalue += (isFirst - 0.5) * level
                            # 对'new'棋子的四个方向进行遍历，若存在对方的高一级别的棋子'newnew'，则value要减小（即吕同学提出的情况）
                            for j in range(4):
                               newnewrow = newrow + directionList[j][0]
                               newnewcol = newcol + directionList[j][1]
                               if newnewrow < 0 or newnewrow > 3 or \
                                    newnewcol < 0 or newnewcol > 7:
                                  pass
                               elif enemySide == self.board.getBelong((newnewrow, newnewcol)) and\
                                    self.board.getValue((newnewrow, newnewcol)) == level + 1:
                                  '''此处表达式可更改，但应保证value要减小，且减小量要比 对象方为先手时的value增量 大'''
                                  invadevalue -= level

                        # 如果此方向为对方空格，则对方可能会隔空击杀，此时value会减小
                        elif enemySide == self.board.getBelong((newrow, newcol)) and\
                              self.board.getValue((newrow, newcol)) == 0:
                            stop = False
                            # 沿该方向前进，若出界，则停下；若碰到对方空格，则继续前进；若碰到对方等级别棋子，则停下并且value减小；其他情况下均停下
                            while not stop:
                              newrow = newrow + directionList[i][0]
                              newcol = newcol + directionList[i][1]
                              # 出界
                              if newrow < 0 or newrow > 3 or \
                                    newcol < 0 or newcol > 7:
                                  stop = True
                              # 碰到对方等级别棋子
                              elif enemySide == self.board.getBelong((newrow, newcol)) and\
                                self.board.getValue((newrow, newcol)) == level:
                                  '''此处的表达式可修改，但应保证value减小'''
                                  invadevalue -= 0.5 * level
                                  stop = True
                              # 碰到对方空格，前进四
                              elif enemySide == self.board.getBelong((newrow, newcol)) and\
                                self.board.getValue((newrow, newcol)) == 0:
                                  stop = False
                              #其他情况，停下
                              else:
                                  stop = True
        return invadevalue
    # 单调性value评估，仅考虑对象方棋盘内的棋子，且对方棋子入侵时，其所在的行与列的value贡献均为0
    def monotonicityValue(self, isFirst):
        import math
        selfSide = isFirst
        monotonicityvalue = 0
        # 遍历每一行
        for row in range(4):
            # 引入单调性因子，表征单行或者单列的单调性好坏
            monotonicityFactor = 0
            # 列数从对象方棋盘的最左列到最右列
            col = (1 - isFirst) * 4
            while col < (1 - isFirst) * 4 + 3:
                # 当前格子的级别
                currentValue = self.board.getValue((row, col))
                # 下一格的坐标
                nextrow = row
                nextcol = col + 1
                # 有内鬼，则终止交易，转至下一行
                if selfSide != self.board.getBelong((row,col)) or\
                        selfSide != self.board.getBelong((nextrow, nextcol)):
                    monotonicityFactor = 0
                    break  # 只是跳出while循环
                # 无内鬼，计算下一格的级别，单调性因子变化
                else:
                    nextValue = self.board.getValue((nextrow, nextcol))
                    '''此表达式可以更改'''
                    monotonicityFactor += nextValue - currentValue
                # 列数加一，继续下一格
                col += 1
            # 此行的单调性因子计算完毕，加至value中
            '''此表达式可以更改'''
            monotonicityvalue += abs(monotonicityFactor)
        # 遍历对象方棋盘每一列
        for col in range((1 - isFirst) * 4, (1 - isFirst) * 4 + 4):
            monotonicityFactor = 0
            row = 0
            while row < 3:
                currentValue = self.board.getValue((row, col))
                nextrow = row + 1
                nextcol = col
                if selfSide != self.board.getBelong((row, col)) or\
                        selfSide != self.board.getBelong((nextrow, nextcol)):
                    monotonicityFactor = 0
                    break
                else:
                    nextValue = self.board.getValue((nextrow, nextcol))
                    monotonicityFactor += nextValue - currentValue
                row += 1
            monotonicityvalue += abs(monotonicityFactor)
        return monotonicityvalue
